home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
333_01
/
awk3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-21
|
32KB
|
1,469 lines
/* awk3.c -- Builtin functions and various utility procedures
Copyright (C) 1986,1987 Free Software Foundation
Written by Jay Fenlason, December 1986
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <errno.h>
#include "awk.h"
struct redirect
{
int flag; /* type of redirection */
NODE *value;
FILE *fp;
};
typedef struct redirect REDIRECT;
static REDIRECT reds[20]; /* An arbitrary limit, surely, but there's an
* arbitrary limit on open files, too. So it
* doesn't make much difference, does it? */
long NR;
int NF;
/* Set all the special variables to their initial values. Also sets up
the dumb[] array for force_string */
VOID PASCAL init_vars(void)
{
register int i;
auto NODE **tmp;
FS_node = spc_var("FS", make_string("[\t ]+", 5));
NF_node = spc_var("NF", make_number(0.0));
RS_node = spc_var("RS", make_string("\n", 1));
NR_node = spc_var("NR", make_number(0.0));
FILENAME_node = spc_var("FILENAME", Nnull_string);
OFS_node = spc_var("OFS", make_string(" ", 1));
ORS_node = spc_var("ORS", make_string("\n", 1));
OFMT_node = spc_var("OFMT", make_string("%.6g", 4));
FNR_node = spc_var("FNR", make_number(0.0));
RLENGTH_node = spc_var("RLENGTH", make_number(0.0));
RSTART_node = spc_var("RSTART", make_number(0.0));
SUBSEP_node = spc_var("SUBSEP", make_string("\034", 1));
ARGC_node = spc_var("ARGC", make_number(1.0));
ARGV_node = variable("ARGV");
assoc_clear(ARGV_node);
tmp = assoc_lookup(ARGV_node, tmp_number((AWKNUM) 0.0), ASSOC_CREATE);
*tmp = make_string(myname, strlen(myname));
/* This ugly hack is used by force_string to fake a call to sprintf */
dumb[0].type = NODE_EXPRESSION_LIST;
dumb[0].lnode = OFMT_node;
dumb[0].rnode = &dumb[1];
dumb[1].type = NODE_EXPRESSION_LIST;
dumb[1].lnode = (NODE *) NULL; /* fill in the var here */
dumb[1].rnode = (NODE *) NULL;
for (i = 0; i < MAXDIM(reds); ++i)
reds[i].flag = NODE_ILLEGAL;
return;
}
/* OFMT is special because we don't dare use force_string on it for fear of
infinite loops. Thus, if it isn't a string, we return the default "%.6g"
This may or may not be the right thing to do, but its the easiest */
/* This routine isn't used! It should be. */
char * PASCAL get_ofmt(void)
{
register NODE *tmp;
tmp = *get_lhs(OFMT_node);
if (tmp->type != NODE_STRING || tmp->stlen == 0)
return("%.6g");
return(tmp->stptr);
}
REPAT_BUFFER * PASCAL get_fs(void)
{
register NODE *tmp;
auto char *err;
auto char *str;
auto int len;
static REPAT_BUFFER fs_repat;
static char fs_fastmap[FASTMAP_SIZE];
static char fs_str[256] = "";
tmp = force_string(FS_node->var_value);
if (0 == tmp->stlen)
{
str = "[\t ]+";
len = strlen(str);
}
else
{
str = tmp->stptr;
len = tmp->stlen;
}
if (strcmp(str, fs_str))
{
strcpy(fs_str, str);
fs_repat.fastmap = fs_fastmap;
fs_repat.used = 0;
fs_repat.fastmap_accurate = FALSE;
fs_repat.can_be_null = 0;
if (0 == fs_repat.allocated)
{
fs_repat.allocated = 100;
if (NULL == (fs_repat.buffer = malloc(100)))
panic("Out of memory for fs_repat buffer");
}
err = re_compile_pattern(str, len, &fs_repat);
if (err)
panic("Invalid REGEXP(%s) in FS variable: %s", str, err);
}
return(&fs_repat);
}
VOID PASCAL set_fs(char *str)
{
register NODE **tmp;
tmp = get_lhs(FS_node);
do_deref();
*tmp = make_string(str, -1);
return;
}
VOID PASCAL set_rs(char *str)
{
register NODE **tmp;
tmp = get_lhs(RS_node);
do_deref();
if (*str == 't')
*str = '\t';
*tmp = make_string(str, 1);
return;
}
int PASCAL get_rs(void)
{
register NODE *tmp;
tmp = force_string(RS_node->var_value);
if (tmp->stlen == 0)
return('\n');
return(*(tmp->stptr));
}
/* Builtin functions */
NODE * PASCAL do_match(NODE *tree)
{
auto int idx;
auto NODE *str, *reg_node;
auto char *err;
auto REPAT_BUFFER *rp;
auto REREGS regs;
get_two(tree, &str, ®_node);
str = force_string(str);
if (NODE_REGEXP == reg_node->type)
rp = reg_node->rereg;
else
{
reg_node = force_string(reg_node);
clear_wrk_repat();
rp = &wrk_repat;
err = re_compile_pattern(reg_node->stptr, reg_node->stlen, rp);
if (err)
panic("Invalid REGEXP(%s) in match(): %s", reg_node->stptr, err);
}
idx = re_search(rp, str->stptr, str->stlen, 0, str->stlen, ®s);
if (idx < 0)
{
assign_number(&RSTART_node->var_value, (AWKNUM) 0.0);
assign_number(&RLENGTH_node->var_value, (AWKNUM) 0.0);
idx = 0;
}
else
{
assign_number(&RSTART_node->var_value, (AWKNUM) ++idx);
assign_number(&RLENGTH_node->var_value,
(AWKNUM) (regs.end[0] - regs.start[0]));
}
return(tmp_number((AWKNUM) idx));
}
NODE * PASCAL do_sub(NODE *tree)
{
auto int idx, len;
auto int match_len;
auto NODE *regexp, *str1, *str2;
auto char *wrk, *pwrk;
auto REPAT_BUFFER *rp;
auto REREGS regs;
get_three(tree, ®exp, &str1, &str2);
str1 = force_string(str1);
str2 = force_string(str2);
if (NODE_REGEXP == regexp->type)
rp = regexp->rereg;
else
{
regexp = force_string(regexp);
clear_wrk_repat();
rp = &wrk_repat;
wrk = re_compile_pattern(regexp->stptr, regexp->stlen, rp);
if (wrk)
panic("Invalid REGEXP(%s) in sub(): %s", regexp->stptr, wrk);
}
idx = re_search(rp, str2->stptr, str2->stlen, 0, str2->stlen, ®s);
if (idx < 0)
return(tmp_number((AWKNUM) 0.0));
match_len = regs.end[0] - regs.start[0];
wrk = malloc(str2->stlen - match_len + str1->stlen + 1);
if (NULL == wrk)
panic("Out of memory in do_sub()");
pwrk = wrk;
if (idx > 0)
{
memcpy(pwrk, str2->stptr, idx);
pwrk += idx;
}
memcpy(pwrk, str1->stptr, str1->stlen);
pwrk += str1->stlen;
len = idx + match_len;
if (len < str2->stlen)
{
memcpy(pwrk, str2->stptr + len, str2->stlen - len);
pwrk += str2->stlen - len;
}
*pwrk = EOS;
len = str2->stlen - match_len + str1->stlen;
str1 = tree->rnode->rnode->lnode;
*get_lhs(str1) = dupnode(tmp_string(wrk, len));
do_deref();
free(wrk);
/* If the modified string is a field variable we need to update the */
/* value of the field variables. If $0 was changed we need to recalc */
/* all the fields. If an individual field was modified we need to */
/* recalc $0. - BW 12/21/88 */
if (NODE_FIELD_SPEC == str1->type)
field_spec_changed(str1->lnode->numbr);
return(tmp_number((AWKNUM) 1.0));
}
NODE * PASCAL do_gsub(NODE *tree)
{
auto int idx, len, strlen;
auto int match_len;
auto int hits = 0;
auto int ofs = 0;
auto NODE *regexp, *str1, *str2;
auto char *cur2, *new2, *p;
auto REPAT_BUFFER *rp;
auto REREGS regs;
get_three(tree, ®exp, &str1, &str2);
str1 = force_string(str1);
str2 = force_string(str2);
if (NODE_REGEXP == regexp->type)
rp = regexp->rereg;
else
{
regexp = force_string(regexp);
clear_wrk_repat();
rp = &wrk_repat;
p = re_compile_pattern(regexp->stptr, regexp->stlen, rp);
if (p)
panic("Invalid REGEXP(%s) in gsub(): %s", regexp->stptr, p);
}
idx = re_search(rp, str2->stptr, str2->stlen, 0, str2->stlen, ®s);
if (idx < 0)
return(tmp_number((AWKNUM) 0.0));
match_len = regs.end[0] - regs.start[0];
strlen = str2->stlen;